/*****************************************************************/ /**
* \file   studio_proj.h
* \brief   高斯投影
 *        中央经线计算公式： double central = static_cast<int>(lon / 3) * 3；
* \author wangyingjie
* \date   April 2025                                                                     *********************************************************************/

#ifndef STUDIO_PROJ_H
#define STUDIO_PROJ_H

#include "studio_macros.h"
#include "studio_geo_const.h"

#define AO_GAUSS3_NO(lon) static_cast<int>(lon / 3.0 + 1)
#define AO_GAUSS6_NO(lon) static_cast<int>(lon / 6.0 + 1)
#define AO_GAUSS3_L0(no) static_cast<double>(3 * no - 1.5)
#define AO_GAUSS6_L0(no) static_cast<double>(6 * no - 3.0)

/* 中央经线计算规范说明 ------------------------------------------------------
 * + 3度分带法 (适用于1:1万~1:50万地图)
 *   - 理论:  3度带中央经线=3度带带号*3.0 , 带号= 3度带带号=(经度+1.5°)/3取整
 *   - 带号计算: int zone_num = floor((经度 + 1.5°) / 3.0);
 *   - 中央经线: double central = floor((经度 + 1.5°) / 3.0) * 3.0;
 *
 * + 6度分带法 (适用于1:1万以下小比例地图)
 *   - 理论:  6度带中央经线=6度带带号*6.0 - 3.0 , 带号= 6度带带号=(经度+6°)/6取整
 *   - 带号计算: zone_num = floor((经度 + 6°) / 6.0);
 *   - 中央经线: double central = floor((经度 + 6°) / 6.0) * 6.0 - 3.0;
 * ----------------------------------------------------------------*/

class proj
{
  public:
    struct param
    {
        // 中央经度线
        double central{117.0};
        double scale{0.9996};
        double easting{500000.0};  // 东偏移
        // 长半轴
        double major_axis{WGS84::A};
        // 扁率
        double flatten{WGS84::F};
    };

  public:
    /// <summary>
    /// 高斯投影反算经纬度
    /// </summary>
    /// <param name="gx"></param>
    /// <param name="gy"></param>
    /// <param name="lon"></param>
    /// <param name="lat"></param>
    /// <param name="p"></param>
    static void gauss_to_lonlat(const double& gx, const double& gy, double& lon, double& lat, const param& p);

    /// <summary>
    /// 高斯投影反算经纬度,使用静态值速度会更快
    /// </summary>
    /// <param name="gx"></param>
    /// <param name="gy"></param>
    /// <param name="lon"></param>
    /// <param name="lat"></param>
    static void gauss_to_lonlat(const double& central, const double& gx, const double& gy, double& lon, double& lat);

    /// <summary>
    /// 经纬度转高斯投影
    /// </summary>
    /// <param name="lon"></param>
    /// <param name="lat"></param>
    /// <param name="gx"></param>
    /// <param name="gy"></param>
    /// <param name="p"></param>
    static void lonlat_to_gauss(const double& lon, const double& lat, double& gx, double& gy, const param& p);

    /// <summary>
    /// 经纬度转高斯投影,使用静态值速度会更快
    /// </summary>
    /// <param name="lon"></param>
    /// <param name="lat"></param>
    /// <param name="gx"></param>
    /// <param name="gy"></param>
    static void lonlat_to_gauss(const double& central, const double& lon, const double& lat, double& gx, double& gy);

    /// <summary>
    /// 墨卡托转经纬度
    /// </summary>
    /// <param name="mctx"></param>
    /// <param name="mcty"></param>
    /// <param name="lon"></param>
    /// <param name="lat"></param>
    static void mercator_to_lonlat(const double& mctx, const double& mcty, double& lon, double& lat);

    /// <summary>
    /// 经纬度转墨卡托
    /// </summary>
    /// <param name="lon"></param>
    /// <param name="lat"></param>
    /// <param name="mctx"></param>
    /// <param name="mcty"></param>
    static void lonlat_to_mercator(const double& lon, const double& lat, double& mctx, double& mcty);

    /// <summary>
    /// 墨卡托转高斯投影
    /// </summary>
    /// <param name="mctx"></param>
    /// <param name="mcty"></param>
    /// <param name="gx"></param>
    /// <param name="gy"></param>
    /// <param name="p"></param>
    static void mercator_to_gauss(const double& mctx, const double& mcty, double& gx, double& gy, const param& p);

    /// <summary>
    /// 高斯投影转墨卡托
    /// </summary>
    /// <param name="gx"></param>
    /// <param name="gy"></param>
    /// <param name="mctx"></param>
    /// <param name="mcty"></param>
    /// <param name="p"></param>
    static void gauss_to_mercator(const double& gx, const double& gy, double& mctx, double& mcty, const param& p);

    /// <summary>
    /// 墨卡托转高斯投影,使用静态值速度会更快
    /// </summary>
    /// <param name="central"></param>
    /// <param name="mctx"></param>
    /// <param name="mcty"></param>
    /// <param name="gx"></param>
    /// <param name="gy"></param>
    static void mercator_to_gauss(const double& central, const double& mctx, const double& mcty, double& gx, double& gy);

    /// <summary>
    /// 高斯投影转墨卡托,使用静态值速度会更快
    /// </summary>
    /// <param name="central"></param>
    /// <param name="gx"></param>
    /// <param name="gy"></param>
    /// <param name="mctx"></param>
    /// <param name="mcty"></param>
    static void gauss_to_mercator(const double& central, const double& gx, const double& gy, double& mctx, double& mcty);

    /// <summary>
    /// 地心地固直角坐标系 转 经纬坐标系
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="z"></param>
    /// <param name="lon"></param>
    /// <param name="lat"></param>
    /// <param name="height"></param>
    static void ecef_to_lonlat(const double& x, const double& y, const double& z, double& lon, double& lat, double& height);

    /// <summary>
    /// 经纬坐标系 转 地心地固直角坐标系
    /// </summary>
    /// <param name="lon"></param>
    /// <param name="lat"></param>
    /// <param name="height"></param>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="z"></param>
    static void lonlat_to_ecef(const double& lon, const double& lat, const double& height, double& x, double& y, double& z);

  private:
};

#endif  //
